package com.lifesting.tool.j2as3.action;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.WildcardType;
import org.eclipse.jdt.core.dom.PrimitiveType.Code;
import org.eclipse.jdt.core.util.IModifierConstants;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.MessageConsole;



public class Util {
	public static final String IS_ABSTRACT = "IS_ABSTRACT";
	public static final String IS_INTERFACE = "IS_INTERFACE";
	public static final String IS_ANONYMOUS = "IS_ANONYMOUS";
	public static final String IS_STATIC = "IS.STATIC";
	public static final String TYPE_NAME_KEY = "TYPE_NAME_KEY";
	public static final String NO_INDENT="NO.INDENT";
	public static final String TRACK_ANONYMOUS_METHODS = "TRACK_ANONYMOUS_METHODS";
	public static final String MORE_THAN_ONE_CONSTRUCTOR = "MORE_THAN_ONE_CONSTRUCTOR";
	public static final String CONSTRUCTOR_BUFFER = "CONSTRUCTOR_BUFFER";
	public static final String QULIFIED_NAME_KEY="QULIFIED_NAME_KEY";
	public static final String CONSTRUCTOR_DESCRIPTOR="CONSTRUCTOR_DESCRIPTOR";
	public static String formatType(org.eclipse.jdt.core.dom.Type type){
		if (type.isArrayType()){
			//TYPE(dimension)
			ArrayType arrayType = (ArrayType)type;
			return arrayType.getElementType()+"["+arrayType.getDimensions()+"]";
		}else if (type.isPrimitiveType()){
			return ((PrimitiveType)type).getPrimitiveTypeCode().toString();
		}else if (type.isSimpleType()){
			return ((SimpleType)type).getName().getFullyQualifiedName();
		}
		else if (type.isQualifiedType()){
			return ((QualifiedType)type).getName().getFullyQualifiedName();
		}else if (type.isParameterizedType()){
//			StringBuffer sb = new StringBuffer();
			Type t = ((ParameterizedType)type).getType();
			/*List ps = ((ParameterizedType)type).typeArguments();
			sb.append(formatType(t)).append('<');
			for (Object pt : ps){
				sb.append(formatType((Type)pt)).append(',');
			}
			sb.append('>');*/
//			return sb.toString();
			return formatType(t);
		}else{
			StringBuffer sb = new StringBuffer();
			sb.append('?');
			WildcardType wt = (WildcardType) type;
			if (wt.getBound() != null){
				if (wt.isUpperBound())
					sb.append(' ').append("extends");
				else
					sb.append(' ').append("super");
				sb.append(' ').append(formatType(wt.getBound()));
			}
			return sb.toString();
		}
	}
	public static final String CONSOLE_NAME="j2as3";
	public static MessageConsole getMessageConsole(){
		 ConsolePlugin plugin = ConsolePlugin.getDefault();
	      IConsoleManager conMan = plugin.getConsoleManager();
	      IConsole[] existing = conMan.getConsoles();
	      for (int i = 0; i < existing.length; i++)
	         if (CONSOLE_NAME.equals(existing[i].getName()))
	            return (MessageConsole) existing[i];
	      MessageConsole myConsole = new MessageConsole(CONSOLE_NAME, null);
	      conMan.addConsoles(new IConsole[]{myConsole});
	      return myConsole;
	}
	public static String getProjectStyle(ITypeRoot root){
		IPackageFragment pr = (IPackageFragment) root.getParent();
		String pf_name = pr.getElementName();
		return pf_name.replace('.', '/')+"/"+root.getElementName();
	}
	public static void cascadeCreateFolder(IFolder folder, IProgressMonitor monitor) throws CoreException {
		// Project always be existed!
		Stack<IFolder> folders = new Stack<IFolder>();
		while (!folder.exists()) {
			folders.push((IFolder) folder);
			folder = (IFolder) folder.getParent();
		}
		// Now parent exists
		while (!folders.isEmpty()) {
			folders.pop().create(true, true, monitor);
		}
	}
	public static String[] getRootPackageFragments(IJavaElement element) throws JavaModelException{
		List<IPackageFragment> fragments = new ArrayList<IPackageFragment>();
		List<String> pkg_filters = new ArrayList<String>();
		IPackageFragmentRoot[] all_roots = element.getJavaProject().getAllPackageFragmentRoots();
		for (IPackageFragmentRoot pfr : all_roots){
			if (pfr.getKind() == IPackageFragmentRoot.K_SOURCE){
				IJavaElement[] pfs = pfr.getChildren();
				for(IJavaElement je : pfs){
					if (je instanceof IPackageFragment){
						IPackageFragment a_pr = (IPackageFragment) je;
						if (a_pr.getChildren().length > 0 && a_pr.getElementName().length() > 1)
							fragments.add(a_pr);
					}
				}
			}
		}
		for (IPackageFragment pft: fragments){
			String pkgName = pft.getElementName();
			boolean found_parent = false;
			for (Iterator<String> iter = pkg_filters.iterator(); iter.hasNext();){
				String iter_name = iter.next();
				if (iter_name.startsWith(pkgName)){ 
					iter.remove();
				}else if (pkgName.startsWith(iter_name)){ 
					if (!found_parent) found_parent = true;
				}
			}
			if (!found_parent)
				pkg_filters.add(pkgName);
		}
		return pkg_filters.toArray(new String[pkg_filters.size()]);
	}
	protected static boolean isAnonymous(ASTNode node) {
		Object is_anonymous = node.getProperty(IS_ANONYMOUS);
		if (is_anonymous != null && is_anonymous == Boolean.TRUE)
			return true;
		return false;
	}
	public static boolean isInterface(ASTNode node){
		Object is_interface = node.getProperty(IS_INTERFACE);
		if (is_interface != null && is_interface == Boolean.TRUE)
			return true;
		return false;
	}
	public static boolean isAbstract(ASTNode node){
		Object is_abstract = node.getProperty(IS_ABSTRACT);
		if (is_abstract != null && is_abstract == Boolean.TRUE)
			return true;
		return false;
	}
	public static boolean isStatic(ASTNode node){
		Object is_static = node.getProperty(IS_STATIC);
		if (is_static != null && is_static == Boolean.TRUE)
			return true;
		return false;
	}
	public static void addModifierProperty(TypeDeclaration node){
		int modifierFlag = node.getModifiers();
		node.setProperty(IS_ABSTRACT, (modifierFlag & IModifierConstants.ACC_ABSTRACT) != 0);
		node.setProperty(IS_INTERFACE, node.isInterface());
		node.setProperty(IS_STATIC, (modifierFlag & IModifierConstants.ACC_STATIC) != 0);
	}
	public static void removeInterModifier(BodyDeclaration node){
		for (Iterator it = node.modifiers().iterator(); it.hasNext(); )
		{
			 Modifier mo = (Modifier) it.next();
			 if (mo.isStatic())
				 it.remove();
			 if (mo.isPrivate())
				 it.remove();
		}
	}
	public static void setName(ASTNode node, String name){
		node.setProperty(TYPE_NAME_KEY, name);
	}
	public static String getName(ASTNode node){
		return (String) node.getProperty(TYPE_NAME_KEY);
	}
	public static boolean hasNoIndent(ASTNode node){
		Object noIndent = node.getProperty(NO_INDENT);
		if (noIndent != null && noIndent == Boolean.TRUE)
			return true;
		return false;
	}
	public static void noIndent(ASTNode node){
		node.setProperty(NO_INDENT, Boolean.TRUE);
	}
	public static String getDefaultValue(Type returnType2) {
		if (returnType2.isPrimitiveType()){
			Code code = ((PrimitiveType)returnType2).getPrimitiveTypeCode();
			if (code == PrimitiveType.INT || code == PrimitiveType.BYTE || code == PrimitiveType.SHORT || code == PrimitiveType.LONG || code == PrimitiveType.DOUBLE || code == PrimitiveType.FLOAT )
				return "return 0;";
			if (code == PrimitiveType.CHAR)
				return "return '';";
			if (code == PrimitiveType.VOID)
				return "return;";
		}
		return "return Null;";
	}
	public static String makeOverrideSignatures(IMethod method){
		StringBuffer sb= new StringBuffer();
		try {
			sb.append(method.getSignature());
			sb.append('@');
			sb.append(method.getElementName());
		} catch (JavaModelException e) {
			e.printStackTrace();
		}
		return sb.toString();
		
	}
	public static boolean overridable(IMethod method){
		try {
			if (method.isConstructor()) return false;
		} catch (JavaModelException e) {
			e.printStackTrace();
			return false;
		}
		int method_flags;
		try {
			method_flags = method.getFlags();
			if ((method_flags & IModifierConstants.ACC_PRIVATE) != 0)
				return false;
			if ((method_flags & IModifierConstants.ACC_FINAL) != 0)
				return false;
			if ((method_flags & IModifierConstants.ACC_STATIC) != 0)
				return false;
		} catch (JavaModelException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	public static void setAnonTrackMethod(AnonymousClassDeclaration anons){
		anons.setProperty(TRACK_ANONYMOUS_METHODS, Boolean.TRUE);
	}
	public static boolean canTrackMethod(ASTNode node)
	{
		Object track_method = node.getProperty(TRACK_ANONYMOUS_METHODS);
		return (track_method != null && track_method == Boolean.TRUE);
	}
	public static void overloadConstructor(ASTNode node){
		node.setProperty(MORE_THAN_ONE_CONSTRUCTOR, Boolean.TRUE);
	}
	public static boolean needMergeConstructor(MethodDeclaration node){
		Object ret = node.getParent().getProperty(CONSTRUCTOR_DESCRIPTOR);
		return node.isConstructor() && ret != null;
	}
	public static void removeConstructorBuffer(ASTNode node){
		StringBuffer sb = (StringBuffer) node.getProperty(CONSTRUCTOR_BUFFER);
		if (sb != null){
			sb.setLength(0);
			node.setProperty(CONSTRUCTOR_BUFFER, null);
		}
	}
	public static void setQn(ASTNode node, String qn){
		node.setProperty(QULIFIED_NAME_KEY, qn);
	}
	public static String getQn(ASTNode node){
		return (String) node.getProperty(QULIFIED_NAME_KEY);
	}
}
